<?php

namespace App\Admin\Controllers\OwnerItem;

use App\Api\Helpers\ApiResponse;
use App\Events\ContractGenerationEvent;
use App\Models\Fund;
use App\Models\HouseFeeConfig;
use App\Models\Meter;
use App\Models\Owner;
use App\Models\OwnerItem;
use App\Models\Room;
use App\Models\User;
use App\Services\EstateService;
use App\Services\MeterService;
use Dcat\Admin\Admin;
use Dcat\Admin\Controllers\AdminController;
use Dcat\Admin\Form;
use Dcat\Admin\Layout\Content;
use Dcat\Admin\Widgets\Alert;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;

class RunningWaterController extends AdminController
{
    use ApiResponse;

    protected $meterService;

    public static $js = [
        '/js/app.js',
    ];

    public function __construct(MeterService $meterService)
    {
        $this->meterService = $meterService;
    }

    /**
     * @param $query
     * @param $searchArr
     */
    private function queryIndex($query, $searchArr)
    {
        // 搜索room_id
        if (isset($searchArr['room_id']) && $roomId = $searchArr['room_id']) {
            $query = $query->where('ownerable_id', $roomId)->where('ownerable_type', Room::class);
        }

        // 搜索user_id
        if (isset($searchArr['user_id']) && $userId = $searchArr['user_id']) {
            $query = $query->where('user_id', $userId);
        }

        return $query;
    }

    /**
     * 未收账单首页界面
     * @param Content $content
     * @return Content
     */
    public function index(Content $content)
    {
        $searchArr = request()->all();

        $query = Owner::query()->where("closed", false);

        $query = $this->queryIndex($query, $searchArr);  // 查询构造器

        Admin::js(static::$js);
        $bill = $query->orderBy("id", "desc")
            ->with(
                [
                    'firstNotPayItem',
                    'user',
                    'lastItem',
                ]
            )->paginate(4);

        $once = HouseFeeConfig::query()->where('type', HouseFeeConfig::TYPE_FIXED)->get();

        $bill->getCollection()->transform(
            function ($owner) {
                if ($owner->config) { // 如果为空
                    $newConfig = [];
                    foreach ($owner->config as $key => $value) {
                        $houseFeeConfig = HouseFeeConfig::query()->find($value['house_config_id']);
                        $newConfig[$key]['name'] = $houseFeeConfig->name;
                        $newConfig[$key]['type'] = $houseFeeConfig->type;
                        $newConfig[$key]['unit'] = $houseFeeConfig->unit;
                        $newConfig[$key]['house_config_id'] = $value['house_config_id'];
                        $newConfig[$key]['price'] = $value['price'];
                        if (isset($owner->firstNotPayItem)) {
                            // 获取上一期的数据
                            if ($owner->firstNotPayItem->total_amount && $owner->firstNotPayItem->count != 1) {
                                $newConfig[$key]['last_meter'] = $this->meterService->getLastLastMeterByOwner(
                                    $owner,
                                    $houseFeeConfig
                                );
                            } else {
                                $newConfig[$key]['last_meter'] = $this->meterService->getLastMeterByOwner(
                                    $owner,
                                    $houseFeeConfig
                                );
                            }
                        }
                    }
                    $owner->config = $newConfig;
                }
                $owner->next_rent_day = $this->getNextRentDays($owner);
                $owner->items_count = OwnerItem::query()->where('owner_id', $owner->id)->count();

                return $owner;
            }
        );

        // 用户列表
        $users = User::query()->whereHas('owner', function ($query) {
            $query->where('closed', false);
        })->get();

        $rooms = Room::query()->with('building.house')->where('is_rent', true)->get();

        // 获取最早一期的订单
        return $content
            ->title('未收账单')
            ->body(view('admin.owner-item.running_water', compact('bill', 'once', 'users', 'rooms')));
    }

    /**
     * 历史账单界面
     * @param Owner $owner
     * @param Content $content
     * @return Content
     */
    public function showHistoryBill(Owner $owner, Content $content)
    {
        // 获取历史已支付的订单
        $owner = $owner->load(
            [
                'items' => function ($query) {
                    $query->whereNotNull('pay_at')->orderBy('pay_at', 'desc');
                },
                'user',
            ]
        );

        return $content
            ->title($owner->user->name.'的历史流水')
            ->body(view('admin.owner-item.history_bill', compact('owner')));
    }

    /**
     * 获取距离下次交租的日期
     * @param $owner
     * @return false|float
     */
    private function getNextRentDays($owner)
    {
        if (isset($owner->firstNotPayItem)) {
            $ended_at = Carbon::parse($owner->firstNotPayItem->ended_at);
            $days = ($ended_at->timestamp - Carbon::now()->timestamp) / (60 * 60 * 24);
        } else {
            $ended_at = Carbon::parse($owner->ended_at);
            $days = ($ended_at->timestamp - Carbon::now()->timestamp) / (60 * 60 * 24);
        }

        return ceil($days);
    }

    /**
     * 管理员确认用户支付逻辑
     * 如果是最后一期合同流水，将会返回提示（是否续约提示）
     * @param OwnerItem $bill
     * @return mixed
     */
    public function pay(OwnerItem $bill)
    {
        // 根据账单加载合同
        $bill->load('owner');

        // 判断是否抄表
        if (!$bill->other_amount && $bill->owner->config) {
            return $this->failed("请抄表！");
        }

        // 用于判断是否为最后一期合同
        $count = OwnerItem::query()->where('owner_id', $bill->owner_id)->count();
        // 是否移除押金
        $removeDeposit = \request()->input('remove_deposit');

        // 最后一期账单，如果当前时间小于合同结束时间， 把will_close设置为true（延迟关闭功能）， 同时确认收款
        if ($count == $bill->count && Carbon::now()->lte($bill->owner->ended_at)) {

            DB::transaction(
                function () use ($bill, $removeDeposit) {

                    // 确认收款
                    $bill->update(
                        [
                            'pay_at' => Carbon::now(),
                            'status' => OwnerItem::STATUS_PAY_SUCCESS,
                        ]
                    );

                    $owner = Owner::query()->where('id', $bill->owner->id)->first();
                    $owner->will_close = true;   //  延迟关闭合同
                    $owner->save();

                    // 是否从本次收入中扣除押金
                    if ($removeDeposit) {
                        // 从本期结算中扣除押金
                        if (doubleval($owner->deposit) < doubleval($bill->total_amount)) {
                            // 押金支出   storeByModel 表示已经支出付款了
                            Fund::storeByModel(Fund::TYPE_DEPOSIT_EXPENSE, $bill->total_amount, $bill, $owner->user_id);

                            $owner->deposit_type = Owner::DEPOSIT_TYPE_RETURN;  // 表示已经把押金退还给了客户
                        } else {
                            $deposit_expense = big_number($owner->deposit)->subtract($bill->total_amount)->getValue();
                            // 计算出要支出的押金, storeNotPayByModel 表示未支出
                            Fund::storeNotPayByModel(Fund::TYPE_DEPOSIT_EXPENSE, $deposit_expense, $bill, $owner->user_id);
                        }
                    } else {
                        // 把押金存入到fund中, storeNotPayByModel 表示未支出
                        Fund::storeNotPayByModel(Fund::TYPE_DEPOSIT_EXPENSE, doubleval($owner->deposit), $bill, $owner->user_id);
                    }

                    // 写入租金
                    Fund::storeByModel(Fund::TYPE_RENTAL_INCOME, $bill->total_amount, $bill, $bill->owner->user_id);
                }
            );

            // 把合同设置为将要关闭
            return $this->message("操作成功，合同将会在合同到期时自动结束合同！");
        }

        // 最后一期合同， 如果当前时间大于合同结束时间， 确认收款， 合同关闭， 解除合同和房间的依赖
        if ($count == $bill->count && Carbon::now()->lte($bill->owner->ended_at)) {

            DB::transaction(function () use ($bill, $removeDeposit){
                // 确认收款
                $bill->update(
                    [
                        'pay_at' => Carbon::now(),
                        'status' => OwnerItem::STATUS_PAY_SUCCESS,
                    ]
                );

                // 合同关闭
                $owner = Owner::query()->where('id', $bill->owner->id)->first();
                $owner->will_close = false;
                $owner->closed = true;
                $owner->save();

                // 解除合同和房间的依赖，把房间设置为可以出租
                (new EstateService())->changeIsRent($owner);

                // 是否从本次收入中扣除押金
                if ($removeDeposit) {
                    // 从本期结算中扣除押金
                    if (doubleval($owner->deposit) < doubleval($bill->total_amount)) {
                        // 押金支出   storeByModel 表示已经支出付款了
                        Fund::storeByModel(Fund::TYPE_DEPOSIT_EXPENSE, $bill->total_amount, $bill, $owner->user_id);

                        $owner->deposit_type = Owner::DEPOSIT_TYPE_RETURN;  // 表示已经把押金退还给了客户
                    } else {
                        $deposit_expense = big_number($owner->deposit)->subtract($bill->total_amount)->getValue();
                        // 计算出要支出的押金, storeNotPayByModel 表示未支出
                        Fund::storeNotPayByModel(Fund::TYPE_DEPOSIT_EXPENSE, $deposit_expense, $bill, $owner->user_id);
                    }
                } else {
                    // 把押金存入到fund中, storeNotPayByModel 表示未支出
                    Fund::storeNotPayByModel(Fund::TYPE_DEPOSIT_EXPENSE, doubleval($owner->deposit), $bill, $owner->user_id);
                }

                // 写入租金
                Fund::storeByModel(Fund::TYPE_RENTAL_INCOME, $bill->total_amount, $bill, $bill->owner->user_id);
            });

            // 把合同关闭成功
            return $this->message("已结束合同！");
        }

        // 普通的确认收款
        DB::transaction(
            function () use ($bill) {
                // 当前流水
                $bill->update(
                    [
                        'pay_at' => Carbon::now(),
                        'status' => OwnerItem::STATUS_PAY_SUCCESS,
                    ]
                );

                // 写入租金
                Fund::storeByModel(Fund::TYPE_RENTAL_INCOME, $bill->total_amount, $bill, $bill->owner->user_id);
            }
        );

        return $this->message("确认收款成功!");
    }

    /**
     * 更新抄表数据逻辑
     * @param OwnerItem $bill
     * @return \Illuminate\Http\RedirectResponse
     */
    public function updateMeter(OwnerItem $bill)
    {
        $bool = DB::transaction(
            function () use ($bill) {
                $data = request()->all();
                unset($data['_token']);

                // 获取合同
                $owner = $bill->owner;

                // 生成以house_config_id为键 price为值的数组
                $arr = array_column($owner->config, "price", "house_config_id");
                // 索引值
                $index = 0;
                // 杂费详细信息
                $otherAmountArr = [];
                // 杂费总金额
                $other_fee = 0;

                // 计算需要抄表费用，并且保存
                foreach ($data as $houseFeeConfigId => $nowMeter) {

                    $houseFeeConfig = HouseFeeConfig::query()->find($houseFeeConfigId);

                    // 获取上一次的抄表对象
                    if ($bill->total_amount && $bill->count != 1) {  // 如果已经存在本期流水总金额，那么表示是更新抄表数据
                        $lastMeter = $this->meterService->getLastLastMeterByOwner($owner, $houseFeeConfig);
                    } else {
                        $lastMeter = $this->meterService->getLastMeterByOwner($owner, $houseFeeConfig);
                    }

                    // 获取读数差值
                    $temp = big_number($nowMeter)->subtract($lastMeter->value);
                    $readingNum = $temp->getValue();
                    // 如果读数差值小于0报错
                    if ($readingNum < 0) {
                        return $this->failed("本期抄表读数不得小于上期抄表读数");
                    }
                    // 费用
                    $fee = $temp->multiply($arr[$houseFeeConfig->id])->getValue();

                    // 杂费详细信息
                    $otherAmountArr[$index]['fee'] = $fee;
                    $otherAmountArr[$index]['house_fee_config_id'] = $houseFeeConfig->id;
                    $otherAmountArr[$index]['name'] = $houseFeeConfig->name;
                    $otherAmountArr[$index]['type'] = $houseFeeConfig->type;
                    $otherAmountArr[$index]['unit'] = $houseFeeConfig->unit;
                    $otherAmountArr[$index]['price'] = $arr[$houseFeeConfig->id];
                    $otherAmountArr[$index]['last_meter'] = $lastMeter->value;
                    $otherAmountArr[$index]['now_meter'] = $nowMeter;
                    $otherAmountArr[$index]['reading_num'] = $readingNum;

                    // 判断流水id是否存在, 流水id存在就更新原本的抄表数据，否则就新增一条抄表数据
                    if (Meter::query()->where('owner_item_id', $bill->id)->where(
                        'house_fee_config_id',
                        $houseFeeConfigId
                    )->exists()) {
                        Meter::query()->where('owner_item_id', $bill->id)
                            ->where('house_fee_config_id', $houseFeeConfigId)
                            ->update(
                                [
                                    'value' => $nowMeter,
                                    'house_fee_config_id' => $houseFeeConfigId,
                                ]
                            );
                    } else {
                        // 创建抄表数据
                        Meter::query()->create(
                            [
                                'value' => $nowMeter,
                                'house_fee_config_id' => $houseFeeConfigId,
                                'count' => $lastMeter->count + 1,
                                'meterable_id' => $lastMeter->meterable_id,
                                'meterable_type' => $lastMeter->meterable_type,
                                'owner_item_id' => $bill->id,
                            ]
                        );
                    }
                    // 计算了抄表数据的杂费总金额
                    $other_fee = big_number($other_fee)->add($fee)->getValue();
                    $index++;
                }

                // 计算每期杂费
                $cycleAmountArray = [];
                $cycleAmount = big_number(0);
                foreach ($owner->config as $config) {
                    $tempId = $config['house_config_id'];
                    if (in_array($tempId, array_keys($data))) {
                        continue;
                    }

                    $houseFeeConfig = HouseFeeConfig::query()->find($tempId);
                    if ($houseFeeConfig->type != HouseFeeConfig::TYPE_CYCLE) {
                        continue;
                    }
                    $cycleAmount->add($config['price']);

                    array_push(
                        $cycleAmountArray,
                        [
                            "fee" => $config['price'],
                            "house_fee_config_id" => $tempId,
                            "name" => $houseFeeConfig->name,
                            "type" => $houseFeeConfig->type,
                            "unit" => $houseFeeConfig->unit,
                        ]
                    );
                }

                $other_fee = $cycleAmount->add($other_fee)->getValue();

                // 保存杂费项
                $bill->other_amount = array_merge($otherAmountArr, $cycleAmountArray);
                // 更新流水时间，设置为抄表时间
                $bill->updated_at = Carbon::now();
                // 计算总金额
                $bill->total_amount = big_number($bill->rent)->add($other_fee)->getValue();
                $bill->save();

                return true;
            }
        );

        if ($bool) {
            admin_success('抄表成功！');
        } else {
            admin_error('抄表失败！未知异常，请联系管理员');
        }

        return response()->redirectTo(route("admin.running-water.index"));
    }

    /**
     * 更新杂费逻辑
     * @param OwnerItem $bill
     * @return \Illuminate\Http\RedirectResponse
     */
    public function updateOtherAmount(OwnerItem $bill)
    {
        $bool = DB::transaction(
            function () use ($bill) {
                $data = request()->all();
                unset($data['_token']);

                // 获取合同
                $owner = $bill->owner;

                // 生成以house_config_id为键 price为值的数组
                $arr = array_column($owner->config, "price", "house_config_id");
                // 索引值
                $index = 0;
                // 杂费详细信息
                $otherAmountArr = [];
                // 杂费总金额
                $other_fee = 0;

                // 计算各项杂费，并且保存
                foreach ($data as $houseFeeConfigId => $nowMoney) {

                    $houseFeeConfig = HouseFeeConfig::query()
                        ->where('type', HouseFeeConfig::TYPE_METER_READING)
                        ->find($houseFeeConfigId);

                    // 获取上一次的抄表对象
                    if ($bill->total_amount) {  // 如果已经存在本期流水总金额，那么表示是更新抄表数据
                        $lastMeter = $this->meterService->getLastLastMeterByOwner($owner, $houseFeeConfig);
                    } else {
                        $lastMeter = $this->meterService->getLastMeterByOwner($owner, $houseFeeConfig);
                    }

                    $price = $arr[$houseFeeConfig->id]; // 单价
                    // 根据单价计算出本次的抄表数值
                    $nowMeter = big_number($nowMoney)->divide($price)->add($lastMeter->value);

                    // 杂费详细信息
                    $otherAmountArr[$index]['fee'] = $nowMoney;
                    $otherAmountArr[$index]['house_fee_config_id'] = $houseFeeConfig->id;
                    $otherAmountArr[$index]['name'] = $houseFeeConfig->name;
                    $otherAmountArr[$index]['type'] = $houseFeeConfig->type;
                    $otherAmountArr[$index]['unit'] = $houseFeeConfig->unit;
                    $otherAmountArr[$index]['price'] = $arr[$houseFeeConfig->id];
                    $otherAmountArr[$index]['last_meter'] = $lastMeter->value;
                    $otherAmountArr[$index]['now_meter'] = $nowMeter->getValue();  // 本期表读数
                    $otherAmountArr[$index]['reading_num'] = $nowMeter->subtract($lastMeter->value)->getValue();  // 使用量

                    // 判断流水id是否存在, 流水id存在就更新原本的抄表数据，否则就新增一条抄表数据
                    if (Meter::query()->where('owner_item_id', $bill->id)->where(
                        'house_fee_config_id',
                        $houseFeeConfigId
                    )->exists()) {
                        Meter::query()->where('owner_item_id', $bill->id)
                            ->where('house_fee_config_id', $houseFeeConfigId)
                            ->update(
                                [
                                    'value' => $nowMeter->getValue(),
                                    'house_fee_config_id' => $houseFeeConfigId,
                                ]
                            );
                    } else {
                        // 创建抄表数据
                        Meter::query()->create(
                            [
                                'value' => $nowMeter->getValue(),
                                'house_fee_config_id' => $houseFeeConfigId,
                                'count' => $lastMeter->count + 1,
                                'meterable_id' => $lastMeter->meterable_id,
                                'meterable_type' => $lastMeter->meterable_type,
                                'owner_item_id' => $bill->id,
                            ]
                        );
                    }
                    // 计算杂费总金额
                    $other_fee = big_number($other_fee)->add($nowMoney)->getValue();
                    $index++;
                }

                // 计算每期杂费
                $cycleAmountArray = [];
                $cycleAmount = big_number(0);
                foreach ($owner->config as $config) {
                    $tempId = $config['house_config_id'];
                    if (in_array($tempId, array_keys($data))) {
                        continue;
                    }

                    $houseFeeConfig = HouseFeeConfig::query()->find($tempId);
                    if ($houseFeeConfig->type != HouseFeeConfig::TYPE_CYCLE) {
                        continue;
                    }
                    $cycleAmount->add($config['price']);

                    array_push(
                        $cycleAmountArray,
                        [
                            "fee" => $config['price'],
                            "house_fee_config_id" => $tempId,
                            "name" => $houseFeeConfig->name,
                            "type" => $houseFeeConfig->type,
                            "unit" => $houseFeeConfig->unit,
                        ]
                    );
                }

                $other_fee = $cycleAmount->add($other_fee)->getValue();

                // 保存杂费项
                $bill->other_amount = $otherAmountArr;
                // 更新流水时间，设置为抄表时间
                $bill->updated_at = Carbon::now();
                // 计算总金额
                $bill->total_amount = big_number($bill->rent)->add($other_fee)->getValue();
                $bill->save();

                return true;
            }
        );

        if ($bool) {
            admin_success('抄表成功！');
        } else {
            admin_error('抄表失败！未知异常，请联系管理员');
        }

        return response()->redirectTo(route("admin.running-water.index"));
    }

    /**
     * 更新一次性付费逻辑
     * @param OwnerItem $bill
     * @param Request $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function updateOnce(OwnerItem $bill, Request $request)
    {
        $bill->load('owner');
        $data = $request->all();
        $once = [];
        $amount = big_number(0);

        if (!isset($data['ids'])) {
            $bill->once = null;
            $bill->total_amount = $this->refreshTotalAmount($bill);
            $bill->save();

            admin_success('流水单号为：' . $bill->id . '的附加收费保存成功！');

            return response()->redirectTo(route("admin.running-water.index"));
        }

        foreach ($data['ids'] as $key => $id) {
            if (in_array($id, array_column($once, 'house_fee_config_id'))) {
                continue;
            }
            $houseFeeConfig = HouseFeeConfig::query()->find($id);
            $once[$key]['house_fee_config_id'] = $id;
            $once[$key]['name'] = $houseFeeConfig->name;
            $once[$key]['fee'] = $data['prices'][$key];
            $amount->add($once[$key]['fee']);
        }

        if ($bill->other_amount) {
            foreach ($bill->other_amount as $value) {
                $amount->add($value['fee']);
            }
        }

        $amount->add($bill->rent);

        $bill->once = $once;
        $bill->total_amount = $amount->getValue();
        $bill->save();

        admin_success('一次性收费性保存成功！');

        return response()->redirectTo(route("admin.running-water.index"));
    }

    /**
     * 重新计算OwnerItem中的totalAmount
     * @param $bill
     * @return string
     */
    private function refreshTotalAmount($bill)
    {
        $total_amount = big_number(0);
        if ($bill->other_amount) {
            foreach ($bill->other_amount as $value) {
                $total_amount->add($value['fee']);
            }
        }

        return $total_amount->add($bill->rent)->getValue();
    }

    /**
     * 续约合同界面
     * @param Owner $owner
     * @param Content $content
     * @return Content
     */
    public function editRenew(Owner $owner, Content $content)
    {
        $form = Form::make(
            new Owner(),
            function (Form $form) use ($owner) {

                $url = route('admin.running-water.index');
                $info = '<i class="fa fa-exclamation-circle"></i> <a style="color: red" href="'.$url.'">点我返回账单界面</a>';
                $form->html(Alert::make($info)->info());

                $form->title('修改合同结束时间， 即可完成合同续约');
                $form->edit($owner->id);
                $form->date('ended_at', '合同结束时间')->help('新的合同结束时间不得小于等于旧的合同结束时间');
                $form->disableDeleteButton();
                $form->disableListButton();
                $form->disableViewButton();
                $form->disableViewCheck();
                $form->disableEditingCheck();
            }
        );


        return $content
            ->title('续约合同')
            ->body($form);
    }

    /**
     * 续约合同逻辑
     * @param Owner $owner
     * @return \Illuminate\Http\JsonResponse|mixed
     */
    public function renew(Owner $owner)
    {
        $end_at = \request()->input('ended_at');

        if ($owner->ended_at >= $end_at) {
            return response()->json(['code' => 200, 'message' => "新的合同结束时间不得小于等于旧的合同结束时间", 'static' => 'error']);
        }
        // 更新合同结束时间
        $owner->update(
            [
                'ended_at' => $end_at,
            ]
        );

        // 判断原本的合同是否是超期合同
        if ($owner->lastItem->type === OwnerItem::TYPE_EXCEED) {
            // 删除最后一期流水，然后重新生成
            $owner->lastItem()->where('id', $owner->lastItem->id)->delete();  // 删除最后一期的数据
        }

        event(new ContractGenerationEvent($owner));   // 重新生成数据avel-admin重定向

        // 续约界面重定向失败， 原因未知（猜测是dcat-admin框架原因）
        return $this->message("续约成功");
    }

    /**
     * 结束合同逻辑
     * @param Owner $owner
     * @return mixed
     */
    public function updateFinish(Owner $owner)
    {
        $owner->load('lastItem');   // 加载最后一期流水数据
        $data = \request()->all();
        // 管理员输入的总金额，（未计算抄表金额）
        $totalAmount = $data['total_amount'];
        if (isset($data['remove_deposit'])) {
            // 如果存在remover_deposit
            $remove_deposit = $data['remove_deposit'];
            unset($data['remove_deposit']);
        }
        unset($data['total_amount']);
        unset($data['_token']);
        unset($data['_method']);
        $nowMeters = $data;

        // 如果不是时间不标准合同直接报错
        if ($owner->lastItem->type == OwnerItem::TYPE_DEFAULT) {
            return $this->failed("非法操作");
        }

        // 提前关闭合同
        if (Carbon::now()->lte($owner->ended_at)) {

            $bool = DB::transaction(function () use ($owner, $nowMeters, $totalAmount) {
                $owner->will_close = true;

                if ($owner->config) {

                    // 获取抄表数据的总金额
                    $meterAmount = $this->getMeterAmount($owner, $nowMeters);

                    if ($meterAmount < 0) {
                        return false;
                    }

                    // 计算总金额
                    $totalAmount = big_number($totalAmount)->add($meterAmount)->getValue();
                }

                $ownerItem = OwnerItem::query()->where('id', $owner->lastItem->id)->first();
                $ownerItem->pay_at = Carbon::now();
                $ownerItem->total_amount = $totalAmount;
                $ownerItem->save();

                // 是否从本次收入中扣除押金
                if (isset($remove_deposit)) {
                    // 从本期结算中扣除押金
                    if (doubleval($owner->deposit) < doubleval($totalAmount)) {
                        // 押金支出   storeByModel 表示已经支出付款了
                        Fund::storeByModel(Fund::TYPE_DEPOSIT_EXPENSE, $totalAmount, $ownerItem, $owner->user_id);

                        $owner->deposit_type = Owner::DEPOSIT_TYPE_RETURN;  // 表示已经把押金退还给了客户
                    } else {
                        $deposit_expense = big_number($owner->deposit)->subtract($totalAmount)->getValue();
                        // 计算出要支出的押金, storeNotPayByModel 表示未支出
                        Fund::storeNotPayByModel(Fund::TYPE_DEPOSIT_EXPENSE, $deposit_expense, $ownerItem, $owner->user_id);
                    }
                } else {
                    // 把押金存入到fund中, storeNotPayByModel 表示未支出
                    Fund::storeNotPayByModel(Fund::TYPE_DEPOSIT_EXPENSE, doubleval($owner->deposit), $ownerItem, $owner->user_id);
                }

                // 租金收入
                Fund::storeByModel(Fund::TYPE_RENTAL_INCOME, $totalAmount, $ownerItem, $owner->user_id);

                $owner->save();

                return true;
            });



            if (!$bool) {
                // 把合同设置为将要关闭
                admin_success('操作失败！无法结束合同');
                return response()->redirectTo(route("admin.running-water.index"));
            }

            // 把合同设置为将要关闭
            admin_success('操作成功，合同将会在合同到期时自动结束合同！');
            return response()->redirectTo(route("admin.running-water.index"));
        }

        // 超出正常日期关闭
        $bool = DB::transaction(
            function () use ($owner, $nowMeters, $totalAmount) {
                // $owner->config 判断公共配置项的值是否为空
                if ($owner->config) {
                    // 获取抄表数据的总金额
                    $meterAmount = $this->getMeterAmount($owner, $nowMeters);
                    if ($meterAmount < 0) {
                        return false;
                    }

                    // 计算总金额
                    $totalAmount = big_number($totalAmount)->add($meterAmount)->getValue();
                }

                // 判断合同类型如果是一般合同
                $lastItem = $owner->lastItem;  // 最后一期流水

                $ownerItem = OwnerItem::query()->where('id', $lastItem->id)->first();
                $ownerItem->total_amount = $totalAmount;
                $ownerItem->pay_at = Carbon::now();
                $ownerItem->save();

                // 是否从本次收入中扣除押金
                if (isset($remove_deposit)) {
                    // 从本期结算中扣除押金
                    if (doubleval($owner->deposit) < doubleval($totalAmount)) {
                        // 押金支出   storeByModel 表示已经支出付款了
                        Fund::storeByModel(Fund::TYPE_DEPOSIT_EXPENSE, $totalAmount, $ownerItem, $owner->user_id);
                        // 租金收入
                        Fund::storeByModel(Fund::TYPE_RENTAL_INCOME, $totalAmount, $ownerItem, $owner->user_id);

                        // 关闭合同
                        Owner::query()->where('id', $owner->id)->update(
                            [
                                'closed' => true,
                                'will_close' => false,
                                'deposit_type' => Owner::DEPOSIT_TYPE_RETURN  // 表示已经把押金退还给了客户
                            ]
                        );
                    } else {
                        $deposit_expense = big_number($owner->deposit)->subtract($totalAmount)->getValue();
                        // 计算出要支出的押金, storeNotPayByModel 表示未支出
                        Fund::storeNotPayByModel(Fund::TYPE_DEPOSIT_EXPENSE, $deposit_expense, $ownerItem, $owner->user_id);

                        // 关闭合同
                        Owner::query()->where('id', $owner->id)->update(
                            [
                                'closed' => true,
                                'will_close' => false
                            ]
                        );
                    }
                } else {
                    // 把押金存入到fund中, storeNotPayByModel 表示未支出
                    Fund::storeNotPayByModel(Fund::TYPE_DEPOSIT_EXPENSE, doubleval($owner->deposit), $ownerItem, $owner->user_id);
                    // 关闭合同
                    Owner::query()->where('id', $owner->id)->update(
                        [
                            'closed' => true,
                            'will_close' => false
                        ]
                    );
                }

                // 把房间的is_rent改为false, 把房间设置为可以出租
                (new EstateService())->changeIsRent($owner);

                return true;
            }
        );

        if (!$bool) {
            admin_error("合同参数异常，请检查电表参数！");
            return response()->redirectTo(route("admin.running-water.index"));
        }

        admin_success('合同关闭成功，租约解除成功！');
        return response()->redirectTo(route("admin.running-water.index"));
    }


    /**
     * 写入抄表数据，并且返回所有表读数的总金额
     * @param Owner $owner
     * @param $nowMeters  array 本期的所有抄表数据
     * @return double
     */
    private function getMeterAmount(Owner $owner, $nowMeters)
    {
        is_array($nowMeters) ?: $nowMeters = [$nowMeters];

        // 给owner新增配置
        $owner = $this->addOwnerConfig($owner);

        $totalAmount = 0;
        $other_amount = [];
        foreach ($owner->config as $item) {

            $houseFeeConfig = HouseFeeConfig::query()->find($item['house_config_id']);

            // 如果公共配置是抄表类型的
            if ($houseFeeConfig->type != HouseFeeConfig::TYPE_METER_READING) {
                continue;
            }

            // 获取上次的抄表数据
            $lastMeter = $this->meterService->getLastMeterByOwner($owner, $houseFeeConfig);

            if ($item['house_config_id'] == $houseFeeConfig->id) {

                // 本期读数
                $nowMeterValue = $nowMeters[$houseFeeConfig->id];

                // 判断上期数据是否大于本期数据
                if ($lastMeter['value'] > $nowMeterValue) {
                    return -1;
                }

                // 保存抄表数据
                Meter::query()->create(
                    [
                        'value' => $nowMeterValue,
                        'house_fee_config_id' => $houseFeeConfig->id,
                        'count' => $lastMeter->count + 1,
                        'meterable_id' => $lastMeter->meterable_id,
                        'meterable_type' => $lastMeter->meterable_type,
                        'owner_item_id' => $owner->lastItem->id
                    ]
                );

                // 计算金额
                $price = $item['price'];
                $readMeter = big_number($nowMeterValue)->subtract($lastMeter->value);

                $tempAmount = $readMeter->multiply($price);

                array_push(
                    $other_amount,
                    [
                        "fee" => $tempAmount->getValue(),
                        "house_fee_config_id" => $houseFeeConfig->id,
                        "name" => $houseFeeConfig->name,
                        "type" => $houseFeeConfig->type,
                        "unit" => $houseFeeConfig->unit,
                        'price' => $price,
                        'last_meter' => $lastMeter['value'],
                        'now_meter' => $nowMeterValue,
                        'reading_num' =>  $readMeter->getValue()
                    ]
                );

                $totalAmount = $tempAmount->add($totalAmount)->getValue();
            }
        }

        if ($other_amount) {
            OwnerItem::query()->where('id', $owner->lastItem->id)->update(
                [
                    'other_amount' => $other_amount,
                ]
            );
        }

        return $totalAmount;
    }

    /**
     * 完善公共收费配置
     * @param Owner $owner
     * @return Owner
     */
    private function addOwnerConfig($owner)
    {
        $newConfig = [];
        foreach ($owner->config as $key => $value) {
            $houseFeeConfig = HouseFeeConfig::query()->find($value['house_config_id']);
            $newConfig[$key]['name'] = $houseFeeConfig->name;
            $newConfig[$key]['type'] = $houseFeeConfig->type;
            $newConfig[$key]['unit'] = $houseFeeConfig->unit;
            $newConfig[$key]['house_config_id'] = $value['house_config_id'];
            $newConfig[$key]['price'] = $value['price'];

            // 获取上一期的数据
            if (isset($owner->firstNotPayItem) && $owner->firstNotPayItem->total_amount) {
                $newConfig[$key]['last_meter'] = $this->meterService->getLastLastMeterByOwner(
                    $owner,
                    $houseFeeConfig
                );
            } else {
                $newConfig[$key]['last_meter'] = $this->meterService->getLastMeterByOwner(
                    $owner,
                    $houseFeeConfig
                );
            }
        }
        $owner->config = $newConfig;

        return $owner;
    }
}
